package io.modifier.basic.core.data.kvCache

import com.google.gson.Gson
import io.modifier.basic.core.appCtx.AppCtx
import io.modifier.basic.core.data.kvCache.cache.CacheProviderMark
import io.modifier.basic.core.data.kvCache.cache.ICache
import io.modifier.basic.core.data.kvCache.cache.impl.MMKVCache
import io.modifier.basic.core.data.kvCache.cache.impl.MemoryCache
import io.modifier.basic.core.data.kvCache.cache.impl.SharedPreferencesCache
import io.modifier.basic.core.data.kvCache.property.KVMapProperty
import io.modifier.basic.core.data.kvCache.property.KVProperty
import io.modifier.basic.core.data.kvCache.property.KVStateFlowProperty

open class KVOwner(override val unique: String, @CacheProviderMark provider: String = CacheProviderMark.MMKV_CACHE) : IKVOwner {
    override val kv: ICache by lazy {
        val ctx = AppCtx.context
        when (provider) {
            CacheProviderMark.MMKV_CACHE -> MMKVCache(ctx, unique)
            CacheProviderMark.SHARED_PREFERENCES_CACHE -> SharedPreferencesCache(ctx, unique)
            else -> MemoryCache()
        }
    }
}

interface IKVOwner {
    val unique: String

    val kv: ICache

    fun genKeyPrefix(): String = "${unique}_"

    private fun <V> Pair<String, V>.save(): Boolean {
        when (second) {
            is Int -> kv.put(first, second as Int)
            is Long -> kv.put(first, second as Long)
            is Boolean -> kv.put(first, second as Boolean)
            is Float -> kv.put(first, second as Float)
            is Double -> kv.put(first, second as Double)
            is String -> kv.put(first, second as String)
            is Set<*> -> kv.put(first, second as Set<String>)
            else -> throw UnsupportedOperationException("不支持的类型")
        }
        return true
    }

    fun kvInt(default: Int = 0) =
        KVProperty(::genKeyPrefix, { kv.getInt(it, default) }, { save() })

    fun kvLong(default: Long = 0L) =
        KVProperty(::genKeyPrefix, { kv.getLong(it, default) }, { save() })

    fun kvBool(default: Boolean = false) =
        KVProperty(::genKeyPrefix, { kv.getBoolean(it, default) }, { save() })

    fun kvFloat(default: Float = 0f) =
        KVProperty(::genKeyPrefix, { kv.getFloat(it, default) }, { save() })

    fun kvDouble(default: Double = 0.0) =
        KVProperty(::genKeyPrefix, { kv.getDouble(it, default) }, { save() })

    fun kvString(default: String = "") =
        KVProperty(::genKeyPrefix, { kv.getString(it, "") }, { save() })

    fun kvStringSet(default: Set<String> = setOf()) =
        KVProperty(::genKeyPrefix, { kv.getStringSet(it, emptySet()) }, { save() })

    fun kvBytes(default: ByteArray = byteArrayOf()) =
        KVProperty(::genKeyPrefix, { kv.getByteArray(it, default) }, { save() })

    fun hasKey(key: String): Boolean = kv.hasKey(genKeyPrefix() + key)

    fun clearAllKV() = kv.clear()

    fun <V> KVProperty<V>.asStateFlow() = KVStateFlowProperty(this)

    fun <V> KVProperty<V>.asMap() = KVMapProperty(this)

}

val gsonIns by lazy { Gson() }

inline fun <reified V> IKVOwner.kvObj(default: V) =
    KVProperty(::genKeyPrefix, { key ->
        kv.getString(key, null)?.let {
            gsonIns.fromJson(it, V::class.java)
        } ?: default
    }, {
        second ?: return@KVProperty false
        kv.put(first, gsonIns.toJson(second))
        return@KVProperty true
    })
